<?php


namespace EasySwoole\EasySwoole;


use App\Crontab\CheckByFdCrontab;
use App\Crontab\CheckScreenFdCrontab;
use App\Handler\WebSocket\ExceptionHandler as WebSocketExceptionHandler;
use App\Utils\LogHelp;
use App\WebSocket\WebSocketEvent;
use App\WebSocket\WebSocketParser;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Config as GlobalConfig;
use EasySwoole\EasySwoole\Crontab\Crontab;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use EasySwoole\ORM\Db\Config;
use EasySwoole\ORM\Db\Connection;
use EasySwoole\ORM\DbManager;
use EasySwoole\Redis\Config\RedisConfig;
use EasySwoole\RedisPool\RedisPool;
use EasySwoole\Socket\Dispatcher;

class EasySwooleEvent implements Event
{
    public static function initialize()
    {
        date_default_timezone_set('Asia/Shanghai');

        // 默认数据库
        $mysqlConfig = new Config(GlobalConfig::getInstance()->getConf("MYSQL"));
        DbManager::getInstance()->addConnection(new Connection($mysqlConfig));

        // redis连接池注册
        try {
            $redisConfig = new RedisConfig(GlobalConfig::getInstance()->getConf("REDIS"));
            $redisPoolConfig = RedisPool::getInstance()->register($redisConfig);
            // 配置连接池连接数
            $redisPoolConfig->setMinObjectNum(5);
            $redisPoolConfig->setMaxObjectNum(20);
        } catch (\Exception $e) {
            LogHelp::error($e->getMessage(), 'redis');
        }

        // 跨域处理 onRequest v3.4.x+
        \EasySwoole\Component\Di::getInstance()->set(\EasySwoole\EasySwoole\SysConst::HTTP_GLOBAL_ON_REQUEST, function (\EasySwoole\Http\Request $request, \EasySwoole\Http\Response $response) {
            $origin = $request->getHeader('origin')[0] ?? '*';
            $response->withHeader('Access-Control-Allow-Origin', $origin);
            $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
            $response->withHeader('Access-Control-Allow-Credentials', 'true');
            $response->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, token');
            if ($request->getMethod() === 'OPTIONS') {
                $response->withStatus(\EasySwoole\Http\Message\Status::CODE_OK);
                return false;
            }
            return true;
        });

        \EasySwoole\Component\Di::getInstance()->set(\EasySwoole\EasySwoole\SysConst::HTTP_EXCEPTION_HANDLER, [\App\Handler\Http\ExceptionHandler::class, 'handle']);
    }

    public static function mainServerCreate(EventRegister $register)
    {
        Crontab::getInstance()->addTask(CheckByFdCrontab::class);
        Crontab::getInstance()->addTask(CheckScreenFdCrontab::class);

        $register->set($register::onWorkerStart,function (\Swoole\Server $server, int $worker_id) {
            // 链接预热
            // ORM 1.4.31 版本之前请使用 getClientPool()
            // DbManager::getInstance()->getConnection()->getClientPool()->keepMin();
            DbManager::getInstance()->getConnection()->__getClientPool()->keepMin();
        });

        // 主服务
        $register->set(EventRegister::onReceive, function (\Swoole\Http\Server $server, int $fd, int $reactor_id, string $data) {
            LogHelp::console("http fd {$fd}");
        });

        /**
         * **************** WEBSOCKET服务 **********************
         */
        // 开启服务
        $websocketServerConfig = GlobalConfig::getInstance()->getConf("WEBSOCKET_SERVER");
        $subWsRegister = \EasySwoole\EasySwoole\ServerManager::getInstance()->getSwooleServer();
        $subWsRegister->addlistener($websocketServerConfig['LISTEN_ADDRESS'], $websocketServerConfig['PORT'], $websocketServerConfig['SOCK_TYPE']);
        // 解析器
        $webSocketConf = new \EasySwoole\Socket\Config();
        $webSocketConf->setType(\EasySwoole\Socket\Config::WEB_SOCKET);// 设置Dispatcher为WebSocket模式
        $webSocketConf->setParser(WebSocketParser::class);// 设置解析器对象
        $webSocketConf->setOnExceptionHandler([WebSocketExceptionHandler::class, 'handle']);
        $webSocketDispatch = new Dispatcher($webSocketConf);// 创建Dispatcher对象并注入config对象
        // 给server注册相关事件在WebSocket模式下onMessage事件必须注册 并且交给Dispatcher对象处理
        $subWsRegister->on(EventRegister::onMessage, function (\Swoole\Websocket\Server $server, \Swoole\Websocket\Frame $frame) use ($webSocketDispatch) {
            $webSocketDispatch->dispatch($server, $frame->data, $frame);
        });
        /*$register->set(EventRegister::onConnect, function (\Swoole\WebSocket\Server $server, int $fd, int $reactor_id) {
            echo "fd {$fd} connected 111\n";
        });*/
        // 自定义握手事件
        $websocketEvent = new WebSocketEvent();
        $subWsRegister->on(EventRegister::onHandShake,function (\Swoole\Http\Request $request, \Swoole\Http\Response $response) use($websocketEvent) {
            $websocketEvent->onHandShake($request,$response);
        });
        // 自定义关闭事件
        $subWsRegister->on(EventRegister::onClose, function (\Swoole\WebSocket\Server $server, int $fd, int $reactorId) use ($websocketEvent) {
            $websocketEvent->onClose($server, $fd, $reactorId);
        });


        ###### 注册 rpc 服务 ######
        $rpcServerConfig = GlobalConfig::getInstance()->getConf("RPC_SERVER");
        /** rpc 服务端配置 */
        $config = new \EasySwoole\Rpc\Config();
        $config->setNodeId('ByEasySwooleRpcNode1');
        $config->setServerName('ByEasySwooleRpc'); // 默认 EasySwoole
        $config->setOnException(function (\Throwable $throwable) {
            LogHelp::error($throwable->getMessage(), 'rpc');
        });

        $serverConfig = $config->getServer();
        // 单机部署内部调用时可指定为 127.0.0.1
        // 分布式部署时多台调用时请填 0.0.0.0
        $serverConfig->setServerIp($rpcServerConfig['SERVER_IP']);
        // 设置工作进程数量
        $serverConfig->setWorkerNum($rpcServerConfig['SETTING']['worker_num']);
        // 设置监听地址及端口 端口可被复用
        $serverConfig->setListenAddress($rpcServerConfig['LISTEN_ADDRESS']);
        $serverConfig->setListenPort($rpcServerConfig['PORT']);
        // 设置服务端最大接受包大小
        $serverConfig->setMaxPackageSize($rpcServerConfig['SETTING']['package_max_length']);
        // 设置接收客户端数据时间
        $serverConfig->setNetworkReadTimeout($rpcServerConfig['SETTING']['network_read_timeout']);

        // rpc 具体配置请看配置章节
        $rpc = new \EasySwoole\Rpc\Rpc($config);

        // 创建 Queue 服务
        $queueService = new \App\RpcService\Queue();
        // 添加 QueueModule 模块到 Queue 服务中
        $queueService->addModule(new \App\RpcService\QueueModule());
        // 添加 Queue 服务到服务管理器中
        $rpc->serviceManager()->addService($queueService);
        // 注册 rpc 服务
        $rpc->attachServer(ServerManager::getInstance()->getSwooleServer());
    }
}